home *** CD-ROM | disk | FTP | other *** search
- Using MAKE
-
- Documentation by Ian Lepore
- This document is NOT copyrighted.
-
- Make is a standard Unix utility which is widely available as a Public
- Domain utility for a variety of operating systems. This document
- describes the usage of the make utility. It is not specific to a
- given implementation of make; features available in your version may
- not be docuemented here.
-
- AUTHOR'S NOTE
-
- The information in this document was culled from Unix manuals and
- my own experience (admittedly limited) in working with the source
- code to a PD make. I apologize in advance for any inaccuracies.
-
- OVERVIEW
-
- Make is a utility designed to assist in keeping files up to date
- when a process exists to convert files from one state to another.
- While it is typically used in the context of developing programs,
- make can be used for other similar tasks, such as maintaining a
- library of archive files. The primary focus of this document will
- be in the use of make as a C programming tool.
-
- For all but the smallest of programming projects, it is convenient
- to break the source code into a number of separate modules. While
- this can improve compile times, it increases the burden on the
- programmer, who now has to remember to recompile recompile all the
- modules that were changed during the edit cycle. Make relieves the
- programmer of this burden by automatically re-compiling only the
- modules which were changed.
-
- Make is driven by command line parameters, and specifications in a
- file (called a 'makefile') which describe the relationships between
- the end program and the source code modules required to generate
- it. When make is run, it reads the makefile, compares the file
- timestamps on the various modules, and invokes the appropriate
- processes to bring everything up to date.
-
- CONVENTIONS
-
- In syntax diagrams, the following conventions are used:
-
- [x] Items appearing in brackets are optional.
-
- x|y Items separated by a vertical bar indicate a choice between
- mutually exclusive items.
-
- ... The elipsis indicates a list of items may be provided.
-
- When discussing the actions of make in relation to file types, the
- following assumptions are made for this document:
-
- .PRG files are executable programs. They are created by a linker
- program, which combines object files and modules extracted
- from libraries into a single executable program file.
-
- .O files are object files. They are the output of a language
- processor such as a C compiler, or an assembler.
-
- .C files contain C source code.
-
- .S files contain assembler language source code.
-
- .H files contain C source code, and are included from within
- other C files, rather than compiled directly.
-
- For the purposes of this document, the following 'natural'
- progression from source code to end program is assumed:
-
- [.C|.S] -> .O -> .PRG
-
- The 'natural progression' is discussed in detail under SUFFIXES.
-
- TERMINOLOGY
-
- Target
-
- A target is the output of a process. It will have one or more
- dependents, and a set of rules or commands describing how the
- dependents are transformed into the target. Syntactically, a
- target appears to the left of a colon in the makefile.
-
- Primary Target
-
- The first target encountered in a makefile is the primary
- target. In the programming context, this would be the
- executable program file.
-
- Dependent
-
- A dependent is a file which is required to create a given
- target. Syntactically, a dependent appears to the right of a
- colon in the makefile. In a programming context, the object
- modules would be the dependents for the executable program, and
- the source code modules would be the dependents for the object
- modules.
-
- Dynamic Dependency
-
- A dynamic dependency is one that is created by make internally
- (as opposed to being specified explicitly within the makefile).
- Dynamic dependencies are created through the SUFFIXES mechanism
- and the builtin rules.
-
- Macro
-
- A macro is a string of characters which are substituted for
- another string as make processes lines from the makefile.
- Several builtin macros are provided by make; additional macros
- may be specified in the makefile or on the command line.
-
- Command
-
- A command is a single line containing a command which is passed
- to the shell (or whatever command execution mechanism exists
- within the operating system). Commands are associated with
- rules and targets. The commands within a rule describe a
- generic process ("this is how to turn C source code files into
- object files"), while the commands associated with a target are
- more specific ("this is how to link together all object modules
- and libraries which make up my program").
-
- Rule
-
- Rules are sets of commands which specify the processes used to
- keep targets up to date. Make has a set of builtin rules, and
- additional rules can be defined in the makefile. The builtin
- rules differ for each implementation of make, and are generally
- appropriate to the environment and compilers which the make
- implementation was designed to support. Some versions of make
- have the builtin rules written into the source code (making them
- difficult to change), and other implementations read the default
- rules from a file such as MAKE.INI, allowing the programmer to
- customize make.
-
- BASIC OPERATION
-
- The basic function of make is to update target files by ensuring
- that all of the dependent files are up to date. This is done by
- comparing the file timestamps of the target and all its dependents.
- When any dependents have a more recent modified date & time than
- the target, the corresponding set of rules is invoked to bring the
- target up to date.
-
- The relationships between targets and dependents are specified in
- the makefile, or can be 'intuited' by make based upon the known
- SUFFIXES and builtin rules. There can be multiple levels of
- dependency between the primary target and the lowest-level
- dependents. For example, the file 'myprog.prg' may depend upon
- 'mymain.o' and 'mysubr.o'. Make will internally determine that
- mymain.o and mysubr.o depend on mymain.c and mysubr.c,
- respectively. (When this occurs, .o files become targets of the .c
- files. In this example, the .c files are the lowest-level
- dependents, but this need not be the case. You may, for example,
- have a process which generates a .c file, such as the lex utility.)
- Make will do a depth-first recursive search to determine which
- files need to be brought up to date.
-
- The basic format of the specifications in a makefile is:
-
- target [target...] : [dependent [dependent...]] [# comment]
- [<tab> [@][command] [# comment]]
- [<tab> [@][command] [# comment]]
-
- The sharp character ('#') is used as a comment delimiter. All
- characters following the sharp on a line are ignored.
-
- Some implementations of make require the <tab> character to be the
- first character on a command line, other implementations will
- accept a space or a <tab>. Command lines are optional. When
- commands are specified, they will be used to process a dependent
- file into the target file. When no command lines are present for a
- given target, builtin rules may be invoked (if they exist for the
- target/dependent combination). When no commands are specified, and
- no builtin rules exist, make will issue an error message similar to
- "don't know how to make (dependent name)".
-
- A trailing backslash ('\') character at the end of a line can be
- used to continue statements onto the following line. The backslash
- must be the last character on the line; if whitespace characters
- appear following the backslash, it does not signal a continuation.
-
- By default, make lists each command line before it is executed. If
- the command is preceeded with the '@' character, it will not be
- listed.
-
- Some implementations of make require at least one dependent to be
- listed on a target line. Other versions will allow a target
- without any dependents, providing that the filetype of the target
- is known via the SUFFIXES mechanism (allowing make to establish a
- dynamic dependency for the target.)
-
- If your version of make includes the end-program filetype (eg,
- .PRG) in its SUFFIXES list, a simple makefile would look like:
-
- myprog.prg:
- (or)
- myprog.prg: myprog.o
-
- (The second format might be required if your version of make
- requires dependents to be listed on a target line.) If your make
- does not implicitly understand the .PRG type, you would need a rule
- specifying how to run the linker after the compile is done:
-
- myprog.prg:
- <tab>linker.prg -o myprog.prg myprog.o lib1.a lib2.a
-
- For a more complex program, additional dependencies might be
- specified, as shown in the following example:
-
- myprog.prg: main.o iosubr.o process.o
- <tab>linker.prg -o myprog.prg main.o iosubr.o process.o lib.a
-
- main.o iosubr.o process.o: myhdr.h
-
- This example shows that there are 3 .o files which must be up to
- date to make myprog.prg. In addition, each of those three modules
- depends on myhdr.h, that is, if myhdr.h has a more recent timestamp
- than any of the .o files, the .o file(s) would have to be brought
- up to date before myprog.prg is updated. (Make will dynamically
- determine that the way to bring the .o files up to date is to
- compile the .c files.)
-
- A common error with make is to define myhdr.h as a dependent of the
- .c files instead of the .o files. Be careful with this: it is the
- .o files which must be current to update myprog.prg, even though it
- is the .c files which contain the references to myhdr.h. The
- reason for this is that make's builtin rules don't describe how to
- transform a .h file into a .c file, which is what would be
- attempted if the dependencies were tied to the .c files. By tying
- the dependency to the .o files, you force make to recompile the .c
- files when myhdr.h is modified, which is in fact the correct way to
- update your program after a modification to a header file.
-
- SUFFIXES
-
- Much of the functionality of make is provided by the SUFFIXES
- mechanism, which consists of the .SUFFIXES 'special target', and a
- set of generic file-transformation rules.
-
- Generally speaking, .SUFFIXES provides a list of 'known' filetypes.
- The rules provide the commands needed to turn certain filetypes
- into other filetypes. The combination of SUFFIXES and rules allows
- make to 'know' that .C files can be turned into .O files, for
- example. So, when make encounters a filename that ends in .O, it
- checks to see if there is a corresponding .C file. If there is,
- and it is more recent than the .O, then make will know that the .C
- file has to be recompiled.
-
- All implementations of make have a builtin list of filetypes in the
- .SUFFIXES special target. You may specify additional types by
- coding a .SUFFIXES line in your makefile. The types you specify in
- the makefile will be added to the end of the internal list. (Of
- course, you generally have to provide rules to go with the suffixes
- you add; these can also be specified in the makefile.) To
- completely replace the internal list with your own list of
- suffixes, code a .SUFFIXES line with no dependents, then code your
- own list, as follows:
-
- .SUFFIXES: # wipe out all known suffixes
- .SUFFIXES: .x .y .z # supply a replacement list
-
- Unless you get involved in customizing your version of make to add
- new language processors that it doesn't already know about, the
- preceeding summary is really all you need to know about SUFFIXES.
- For those who need in-depth info, the following paragraphs provide
- a more detailed look at how the SUFFIXES mechanism functions.
-
- A rule is indicated by a special format of a target-with-commands
- sequence which has no dependents. The target name for a rule is
- the concatenation of the filetypes involved in the transformation.
- The leading '.' in a rule's target name is what make keys on to
- distinguish a rule from a normal target/command sequence.
-
- To implement the assumptions about the 'natural progression' of
- source-to-executable that is mentioned in the CONVENTIONS section,
- the following builtin rules would be implemented in make:
-
- .SUFFIXES: .prg .o .s .c
-
- .c.prg: # Turn a .c into a .prg
- cc $< -o $@
-
- .c.o: # Turn a .c into a .o
- cc -c $<
-
- .s.o: # Turn a .s into a .o
- asm $<
-
- This example assumes that the 'cc' program knows how to run the
- linker as well as the compiler, and that it will do so unless the
- '-c' flag is used. This is fairly typical of C compilers.
-
- '$<' is a special macro that works only within builtin rules. '$@'
- is a builtin macro that works anywhere. When a builtin rule is
- invoked by make, the $< will be replaced by the full name
- (including filetype) of the dependent file which triggered the
- rule. (Another builtin macro for rules, '$*', will be replaced
- with the basename (without suffix) of the dependent that triggered
- the rule.) The $@ will be replaced by the full name of the target
- which is being made. Therefore, if the .c.prg rule was invoked to
- update myprog.prg, the command line would expand into:
-
- cc myprog.c -o myprog.prg
-
- For each target and dependent name make encounters when processing
- the makefile, it invokes the SUFFIXES mechanism to try to establish
- a dynamic dependency. When new dependents are added to a target
- via this mechanism, they are also potential targets, and an attempt
- is made to establish dynamic dependency for them as well. This
- process continues recursively until no further levels of dependency
- can be established.
-
- When the SUFFIXES mechanism is invoked, it performs as follows:
-
- - The filename to be checked is separated into a basename and a
- suffix (by splitting it at the last '.' character). For
- example, myprog.o would be split into a basename of 'myprog',
- and a suffix of '.o'.
-
- - Loop for each suffix found in the .SUFFIXES list:
-
- - The suffix from the filename is concatenated behind the
- suffix from the list. For example, the first check would be
- for '.prg.o' (.o from the filename, and .prg from the list).
-
- - Loop for each builtin rule:
-
- - Check to see if the rule matches the current concatention
- of suffixes. For example, the first iteration of the outer
- loop would fail, because there is no '.prg.o' rule. The
- last iteration of the outer loop would build a concatention
- of '.c.o', and a rule for this transformation does exist.
-
- - If a rule does exist for the current combination, the
- filetype from the suffixes list is concatenated to the
- file's basename. An attempt is made to get the timestamp
- for the resulting filename. If the attempt fails, there is
- no such file, and processing continues with the next rule.
- If the file does exist, its timestamp is compared with that
- of the target. If the target needs to be updated, a
- dependency is dynamically added, and the $< and $* macros
- are set to the fullname and basename of the dependent. For
- example, if myprog.c had a more recent timestamp than
- myprog.o, myprog.c would be added as a dependent of
- myprog.o.
-
- It should be mentioned that make is sensitive to the order of the
- filetypes in .SUFFIXES, and the order the rules are listed. The
- .SUFFIXES are tried in a left-to-right sequence, and the list of
- builtin rules is scanned in the order that they are specified (in
- the MAKE.INI file). The first valid combination of the current
- filetype with a type in .SUFFIXES that has a corresponding rule
- will be used. This is generally only important when you are
- building or adding to the builtin rules for your version of make.
-
- MACROS
-
- Macros provide a simple string-substitution facility for make.
- Macros may be defined in the makefile, on the command line, and in
- the MAKE.INI file (if such exists). In addition, make provides
- several builtin macros.
-
- A macro is defined when make sees a name to the left of an '='.
- All the characters on the line which follow the '=' (up to a sharp
- character, if one is present) are the string value assigned to the
- macro. The following are all valid macro definitions:
-
- RE/OPTIONS = -f -a -z2
- 2 = 27
- OBJ = main.o subr1.o subr2.o \
- subr3.o
-
- By convention, macro names are usually specified in uppercase, but
- lower and mixed case names are syntactically legal. As can be seen
- in the example, make places virtually no restrictions on the name
- of a macro. The last example demonstrates a continuation line.
- Note that the leading whitespace on the continuation line is
- removed by the continuation line mechanism.
-
- If a macro is defined multiple times, the most recently encountered
- value is used. A macro can be redefined to have a null value by
- coding 'name=' with no value to the right of the '='.
-
- To refer to a macro in the makefile, it is coded as $(name). For
- example, the following lines from a makefile:
-
- OBJ = main.o subr1.o subr2.o subr3.o
-
- myprog.prg: $(OBJ)
- <tab>linker.prg -o myprog.prg $(OBJ)
-
- $(OBJ): myprog.h
-
- Would be expanded as:
-
- myprog.prg: main.o subr1.o subr2.o subr3.o
- <tab>linker.prg -o myprog.prg main.o subr1.o subr2.o subr3.o
-
- main.o subr1.o subr2.o subr3.o: myprog.h
-
- If a macro is referred to which has never been defined, a null
- string is substituted for the macro, and no error or warning is
- given.
-
- In addition to macros defined by the user, make provides several
- builtin macros, which may be used in command lines, as follows:
-
- $@ - The full name of the current target.
- $? - The list of dependents which triggered this target to be
- remade.
- $< - The full name of the current dependent.
- $* - The base name of the current dependent.
-
-
- The $@ and $? macros are available within any command line in the
- makefile. The $< and $* macros are only valid within rules of the
- the form '.name1.name2:', as descibed in the SUFFIXES section.
-
- Given the following example makefile:
-
- LFLAGS = -m -s
- OBJ = main.o subr1.o subr2.o subr3.o
-
- myprog.prg: $(OBJ)
- <tab>linker.prg $(LFLAGS) -o $@ $(OBJ)
- <tab>size.prg $?
-
- If make determined that main.o and subr2.o were out of date, it
- would find and recompile main.c and subr2.c (thru the SUFFIXES
- mechanism), then it would execute the following 2 commands:
-
- linker.prg -m -s -o myprog.prg main.o subr1.o subr2.o subr3.o
- size.prg main.o subr2.o
-
- As you can see, this makefile causes the program be rebuilt, and it
- also calls the 'size' program to report on the new object module
- sizes, only for the modules which were changed.
-
- Most versions of make define several 'standard' macros in the
- MAKE.INI file, which work in conjunction with the builtin rules.
- The most prevelent of these is CFLAGS, used to allow the programmer
- to override default compiler options. For example, the MAKE.INI
- file (or builtin rules) might contain the following:
-
- CFLAGS =
-
- .c.o:
- <tab>cc $(CFLAGS) -c $<
-
- The initial definition 'CFLAGS =' will define the CFLAGS macro as
- having a null value. If the programmer codes a makefile such as:
-
- CFLAGS = -O
-
- myprog.prg:
- <tab>linker.prg -o myprog.prg myprog.o
-
- Then when make's builtin rule is invoked to compile myprog.c, the
- '-O' option will be passed to the compiler.
-
- SPECIAL TARGETS
-
- In addition to the .SUFFIXES and .name1.name2 special targets which
- are described in the SUFFIXES section, most implementations of make
- define several other 'special' targets. Generally, these are used
- to set switches and options from within a makefile which are
- normally specified on the command line. The most common of these
- special targets are:
-
- .IGNORE Run in 'ignore return codes' mode. (Command line -i)
- .SILENT Run in 'silent' mode. (Command line -s)
- .PRINT Print out structures before making. (Command line -p)
- .NORUN Pretend to make; don't execute cmds. (Command line -n)
- .DEBUG Print debugging info. (Command line -d)
-
- When these targets are encountered in a makefile (or MAKE.INI),
- they cause the appropriate options to take effect, just as if they
- had been specified on the command line. Do not specify any
- dependents or commands with these targets. For example, to set
- silent mode and debug mode, specify the following in the makefile:
-
- .SILENT:
- .DEBUG:
-
- myprog.prg: #etc, etc
-
- COMMAND LINE PARAMETERS
-
- When make is run, it can accept 3 types of command line parameters:
-
- - Options
- - Macros
- - Targets
-
- The options available will vary with each implementation. The
- general format of the make commandline is:
-
- make [options] [macros] [targets]
-
- Note that all parameters are optional; if no parameters are
- specified, make will search the current directory for a file named
- 'makefile', and will process it to make the primary target.
-
- The options available are:
-
- -d Debug mode. Print copious amounts of debugging information
- as the program runs. Useful mainly for debugging a new
- MAKE.INI file.
-
- -f Alternate input file. If, for some reason, the
- specifications for your project are in a file with a name
- other than 'makefile', this flag can be used to provide the
- name of the specifications file. Typically, this must be
- the last option on the command line (preceeding any macros
- or targets). The name of the alternate input file is
- specified following the -f.
-
- -i Ignore return codes mode. Most programs (commands) will
- exit with a return code (or status code) of 0 to indicate
- success. By default, make will stop processing if any
- command returns a non-zero value. This flag overrides this
- option, and allows make to continue processing regardless
- of the return codes from commands.
-
- -n Norun mode. Make will list all the commands that would be
- executed based on the current file timestamps, but it
- doesn't actually execute anything.
-
- -p Print mode. This option causes make to print out the
- contents of all internal data structures before it begins
- executing commands. Useful for debugging.
-
- -q Query mode. Causes make to check whether everything is up
- to date, and exit with a zero return code if so. If any
- file is not up to date, a non-zero return code is set, but
- make does not run any commands to update files.
-
- -r Don't use builtin rules. This option disables the internal
- .SUFFIXES and builtin rules.
-
- -s Silent mode. By default, make lists each command as it is
- executed (unless the first character on the command line is
- '@'). This option causes make to execute all commands
- without listing them.
-
- -t Touch mode. Instead of running commands to bring files up
- to date, touch mode will update the file timestamps
- directly. Use with caution.
-
- When macros are specified on the command line, they are entered
- just as they would be in the makefile. They must follow any
- options, if options are specified. For example:
-
- make -s -f altmake CFLAGS=-O
-
- Would run make using the 'silent' option, using an input file of
- 'altmake' instead of 'makefile', and the CFLAGS macro would be set
- to a value of '-O'.
-
- When targets are specified on the command line, make will attempt
- to locate the targets and make them, instead of defaulting to the
- primary target (the first target found in the makefile). This can
- serve several purposes. If the make implementation supports the
- end-program filetype via the SUFFIXES mechanism (eg, when make
- knows how to turn a .c file into a .prg file), then no makefile is
- needed. Using a command such as:
-
- make CFLAGS=-O myprog.prg
-
- Make will automatically locate myprog.c, compile it using the '-O'
- compiler flag, and will run the linker to create myprog.prg.
-
- In addition to the command line targets used in conjunction with
- the builtin rules, they can be used to make a target from the
- makefile which is not the primary target. This can be thought of
- as an 'alternate entry point' to the makefile. Given the example:
-
- OBJS = main.o subr1.o subr2.o
- FILES = main.c subr1.c subr2.c myprog.h
-
- myprog.prg: $(OBJS)
- <tab>linker.prg -o $@ $(OBJS)
-
- $(OBJS): myprog.h
-
- cleanup:
- <tab>delete $(OBJS)
-
- backup:
- <tab>archive add bkpfile.arc $(FILES)
-
- When make is executed without any targets specified on the command
- line, myprog.prg would be made as normal. Because the targets
- 'cleanup' and 'backup' don't have any dependents (explicitly or
- dynamically), they would not trigger any commands to execute.
- However, if make were run with the target name 'cleanup' on the
- command line, all the object files would be deleted. If make were
- run with the target name 'backup' on the command line, the files
- which make up the source code for the project would automatically
- be archived. Make could be run with both the cleanup and archive
- targets named, and both associated actions would be taken.
-
- MYSTERY FEATURE
-
- Make supports a feature which I have been unable to dig out any
- documentation for, so I'll present it here for what it's worth:
-
- A target name can be followed by a double colon, as follows:
-
- mylib.a:: dependent
- <tab># command
-
- It seems (from looking at incredibly convoluted source code) that
- this provides some sort of feature in which a target can appear
- lots of times in a makefile, having different commands associated
- with each target/dependent combination. Don't take my word for it,
- though.
-
- IMPLEMENTATION-SPECIFIC FEATURES
-
- Each of the PD make implementations I've seen has included a small
- doc file which lists the features and extensions supported (or not
- supported). If your version of make didn't include any docs,
- you'll just have to experiment to find out what features work.
-
- HOW THIS DOCUMENT CAME TO BE
-
- Invariably, the little doc files that come with a PD make contain a
- statement such as "This is not the appropriate forum for a full
- discussion on how MAKE functions." The doc file then refers you to
- 'Unix Documentation', although it's never more specific than that.
-
- After spending several frustrating weeks combing book stores (and
- finding that most Unix books don't even *mention* make), I finally
- got my hands on a proper Unix System Tools manual. Using clues
- garnered from this (rather cryptic) description of make, I went
- back to the (rather cryptic) PD source code and puzzled out in
- depth how make functions.
-
- Then I wrote this document so that PD implementations of make can
- now include more than a version-specific README file. If you are
- porting or writing a PD or shareware (or whatever) version of make,
- please feel free to include this document file with your version.
-
- Ian Lepore (BIX userid ianl)
- 06/06/90
-
-